package cn.kgc.javaweb.servlet;

import cn.hutool.captcha.LineCaptcha;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import cn.kgc.javaweb.entity.User;
import cn.kgc.javaweb.service.UserService;
import cn.kgc.javaweb.service.impl.UserServiceImpl;
import cn.kgc.javaweb.util.JsonResultWriter;
import cn.kgc.javaweb.util.PageDate;
import cn.kgc.javaweb.util.ResponseResult;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * @author: mosin
 * @version: v1.0  2022/10/31
 * 用户请求处理类
 * /user?method=register
 */
@WebServlet("/user")
public class UserServlet extends BaseServlet {

    private UserService userService = new UserServiceImpl();

    // 注册
    protected void register(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        //获取用户注册信息
        String username = req.getParameter("username");
        // 根据用户名查询数据库  数据库中是否存在该用户名

        String password = req.getParameter("password");
        String tel = req.getParameter("tel");
        String address = req.getParameter("address");
        String birth = req.getParameter("birth");  //  2022-10-31  2022/10/31

        Date dataBirth = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            dataBirth = simpleDateFormat.parse(birth);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //封装数据  MD5    密码加密
        User user = User.builder().username(username).password(SecureUtil.md5(password)).address(address).tel(tel).birth(dataBirth).build();

        // 调用业务层的注册业务  user
        Boolean b = userService.register(user);
        System.out.println("b = " + b);
        //  根据业务层的结果 作出响应

        if (b) { //  注册成功 跳转登录页
            resp.sendRedirect(req.getContextPath() + "/login.jsp");
            return;
        }

        req.setAttribute("info", "注册失败");
        req.getRequestDispatcher("/register.jsp").forward(req, resp);


    }

    // 登录
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String token = req.getParameter("token");

        //  1.验证用户输入的验证码是否正确
        String code = (String) req.getSession().getAttribute("code");
        if (code.equals(token)) {
            //  根据用户名进行数据的查询
            User user = userService.login(username);

            if (user == null) {
                req.setAttribute("msg", "用户名错误");
                req.getRequestDispatcher("/login.jsp").forward(req, resp);
            } else {  // 用户存在  需要进一步的判定密码是否正确
                //  加密后的密码
                String pwd = user.getPassword();
                if (pwd.equals(SecureUtil.md5(password))) {  // 跳转主页面

                    // 登录成功之后 需要将用户信息 响应给前端页面 进行数据的展示
                    req.getSession().setAttribute("user", user);

                    //resp.sendRedirect(req.getContextPath()+"/main.jsp");

                    //  先查询所有用户的信息   跳转页面到 main.jsp     UserServlet   findAll()
                    //resp.sendRedirect(req.getContextPath()+"/user?method=findAll");

                    // 跳转分页接口
                    resp.sendRedirect(req.getContextPath() + "/user?method=selectPage&currentPage=1&limit=2");

                } else { //  密码不正确  跳转登录页
                    req.setAttribute("msg", "密码不对");
                    req.getRequestDispatcher("/login.jsp").forward(req, resp);
                }
            }

        } else {   //  验证码不正确  将页面跳转到登录页 并且携带错误信息
            req.setAttribute("msg", "验证码错误");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }

    }

    //验证用户名
    protected void checkUserName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String username = req.getParameter("username");
        System.out.println("username = " + username);

        //  调用用户的业务层进行用户名的校验
        Boolean b = userService.checkUserName(username);
        //  根据查询的结果 响应数据给前端浏览器     html  json   {code:200,msg:"ok",data:user}
        ResponseResult responseResult = ResponseResult.builder().build();
        if (b) {
            responseResult.setCode(200);
            responseResult.setMsg("用户名可用");
        } else {
            responseResult.setCode(500);
            responseResult.setMsg("用户名不可用");
        }
        // 通过工具类作出响应
        JsonResultWriter.writerJson(resp, responseResult);

        //  响应数据的格式 可以通过map集合的形式进行返回
        //HashMap<String, Object> map = new HashMap<>();
        //map.put("code", 500);
        //map.put("msg", "ok");

    }

    //  生成验证码
    protected void getCode(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //  包含干扰线的验证码图片  width  图片宽度  height：图片高度  codeCount 验证码的位数  lineCount  干扰线的条数
        LineCaptcha lineCaptcha = new LineCaptcha(100, 60, 4, 5);
        // 获取图片中的验证码 保存在session会话对象中 用于后续登录验证
        String code = lineCaptcha.getCode();
        System.out.println("code = " + code);
        req.getSession().setAttribute("code", code);

        //将图片以流的形式响应给前端浏览器
        ServletOutputStream outputStream = resp.getOutputStream();
        lineCaptcha.write(outputStream);
        outputStream.close();

    }


    // 查询所有
    protected void findAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //  调用业务层 查询所有用户信息
        List<User> users = userService.findAll();
        req.setAttribute("users", users);
        req.getRequestDispatcher("/main.jsp").forward(req, resp);

    }


    // 添加
    protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        //获取用户注册信息
        String username = req.getParameter("username");
        // 根据用户名查询数据库  数据库中是否存在该用户名

        String password = req.getParameter("password");
        String tel = req.getParameter("tel");
        String address = req.getParameter("address");
        String birth = req.getParameter("birth");  //  2022-10-31  2022/10/31

        Date dataBirth = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            dataBirth = simpleDateFormat.parse(birth);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //封装数据  MD5    密码加密
        User user = User.builder().username(username).password(SecureUtil.md5(password)).address(address).tel(tel).birth(dataBirth).build();

        // 调用业务层的注册业务  user
        Boolean b = userService.register(user);

        if (b) {
            //将页面跳转主页面   /user?method=findAll    main.jsp
            resp.sendRedirect(req.getContextPath() + "/user?method=findAll");
        } else {
            req.setAttribute("msg", "添加用户失败");
            req.getRequestDispatcher("/add.jsp").forward(req, resp);
        }

    }


    // 根据用户名进行查询用户信息  跳转更新页
    protected void toUpdate(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String username = req.getParameter("username");
        User user = userService.findByUserName(username);

        req.setAttribute("user", user);
        req.getRequestDispatcher("/update.jsp").forward(req, resp);

    }


    // 修改用户
    protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String username = req.getParameter("username");
        Long id = Long.valueOf(req.getParameter("id"));
        String tel = req.getParameter("tel");
        String address = req.getParameter("address");
        String birth = req.getParameter("birth");  //  2022-10-31  2022/10/31

        Date dataBirth = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            dataBirth = simpleDateFormat.parse(birth);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        User user = User.builder().username(username).id(id).address(address).tel(tel).birth(dataBirth).build();

        Boolean b = userService.updateUserById(user);

        if (b) {
            resp.sendRedirect(req.getContextPath() + "/user?method=findAll");
        } else {  // 更新失败
            req.setAttribute("msg", "更新失败");
            req.setAttribute("user", user);  //  更新失败  将用户数据回显
            req.getRequestDispatcher("/update.jsp").forward(req, resp);
        }

    }


    // 删除用户
    protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Long id = Long.valueOf(req.getParameter("id"));

        Boolean b = userService.deleteById(id);
        if (!b) {
            req.getSession().setAttribute("msg", "删除失败");
        }
        resp.sendRedirect(req.getContextPath() + "/user?method=findAll");

    }


    // 重置密码
    protected void resetPwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        Long id = Long.valueOf(req.getParameter("id"));

        Boolean b = userService.resetPwd(id);
        if (b) {
            req.getSession().setAttribute("msg", "密码重置成功");
        } else {
            req.getSession().setAttribute("msg", "密码重置失败");
        }
        resp.sendRedirect(req.getContextPath() + "/user?method=findAll");
    }


    //分页查询

    protected void selectPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //  实现分页的两个必要数据   当前页 currentPage   每页显示的条数  limit
        Integer currentPage = Integer.valueOf(req.getParameter("currentPage"));
        Integer limit = Integer.valueOf(req.getParameter("limit"));

        PageDate pageDate = userService.selectPage(currentPage, limit);

        req.setAttribute("pageDate", pageDate);
        req.getRequestDispatcher("/main.jsp").forward(req, resp);

    }


    //头像的上传
    protected void upload(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        //FileItemFactory 接口
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);

        // 用servletFileUpload 文件上传的对象   解析请求 req  username  password  file
        try {
            // List<FileItem>    FileItem  表单中的数据解析完成后 全部封装成FileItem  类型的对象
            List<FileItem> fileItems = servletFileUpload.parseRequest(req);
            // 遍历集合
            fileItems.forEach(fileItem -> {
                //判定当前的fileItem 是不是一个普通的表单元素  username  password
                boolean formField = fileItem.isFormField();
                if(!formField){  //  文件控件
                    try {
                        //获取文件类型 重新给图片命名  唯一
                        String name = fileItem.getName();
                        System.out.println("name = " + name);  //  1.png
                        // 获取文件扩展名
                        String fileExtend = name.substring(name.lastIndexOf("."));
                        //生成图像 唯一的名字   xxxx-xxxx-xxxx
                        String uuid = UUID.randomUUID().toString().replace("-","");
                        // 拼接图像名称
                        String lastName = uuid+fileExtend;
                        File file = new File("D://upload", lastName);

                        // 将文件的名字  写入数据库   user   img   根据用户的id 更新用户头像
                        User user = (User) req.getSession().getAttribute("user");
                        Long id = user.getId();
                        Boolean  b =   userService.updateImg(lastName,id);
                        if(b){
                            fileItem.write(file);
                            System.out.println("文件上传成功");
                            // 跳转主页面  更新session中的user信息
                            user.setImg(lastName);
                            req.getSession().setAttribute("user", user);
                            resp.sendRedirect(req.getContextPath()+"/user?method=selectPage&currentPage=1&limit=2");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });

        } catch (FileUploadException e) {
            e.printStackTrace();
        }


    }


    //获取头像
    protected void getImg(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{

        String imgName = req.getParameter("imgName");
        System.out.println("imgName = " + imgName);

        //  d://upload  imgName
        File file = new File("D://upload", imgName);
        // 通过输入流 读取用户头像
        FileInputStream fileInputStream = new FileInputStream(file);

        // 获取输出流将头像的文件输出到前端页面
        ServletOutputStream outputStream = resp.getOutputStream();

        // 流的拷贝
        IOUtils.copy(fileInputStream, outputStream);

        //释放资源
        outputStream.close();
        fileInputStream.close();

    }


    // 下载头像
    protected void downloadImg(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{


        String imgName = req.getParameter("imgName");

        //  d://upload  imgName
        File file = new File("D://upload", imgName);
        // 通过输入流 读取用户头像
        FileInputStream fileInputStream = new FileInputStream(file);

        FileInputStream in =   new FileInputStream(file);

        //任意的文件
        resp.setContentType("application/octet-stream; charset=utf-8");
        //设置以附件形式打开  通过URLEncoder 解决下载文件中文乱码问题
        resp.setHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode("下载.png", "UTF-8"));

        // 获取输出流将头像的文件输出到前端页面
        ServletOutputStream outputStream = resp.getOutputStream();
        // 流的拷贝
        IOUtils.copy(fileInputStream, outputStream);
        //释放资源
        outputStream.close();
        fileInputStream.close();


    }



    //退出登录  logout
    protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{

        // 退出登录  销毁当前请求对应的session对象
        HttpSession session = req.getSession();
        session.invalidate();  //  销毁session    //  30min
        // 跳转登录页
        resp.sendRedirect(req.getContextPath()+"/login.jsp");

    }

}
